# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: site-packages\PyInstaller\compat.py
"""
Various classes and functions to provide some backwards-compatibility
with previous versions of Python from 2.7 onward.
"""
from __future__ import print_function
import io, os, platform, site, subprocess, sys
from .log import logger

is_py2 = sys.version_info[0] == 2
is_py3 = sys.version_info[0] == 3
is_py27 = sys.version_info >= (2, 7) and sys.version_info < (3, 0)
is_py34 = sys.version_info >= (3, 4)
is_py35 = sys.version_info >= (3, 5)
is_py36 = sys.version_info >= (3, 6)
is_py37 = sys.version_info >= (3, 7)
is_win = sys.platform.startswith("win")
is_cygwin = sys.platform == "cygwin"
is_darwin = sys.platform == "darwin"
is_linux = sys.platform.startswith("linux")
is_solar = sys.platform.startswith("sun")
is_aix = sys.platform.startswith("aix")
is_freebsd = sys.platform.startswith("freebsd")
is_hpux = sys.platform.startswith("hp-ux")
is_unix = is_linux or is_solar or is_aix or is_freebsd or is_hpux
_pyver = sys.version_info[:2]
if is_win:
    PYDYLIB_NAMES = {"python%d%d.dll" % _pyver, "libpython%d.%d.dll" % _pyver}
else:
    if is_cygwin:
        PYDYLIB_NAMES = {
            "libpython%d%d.dll" % _pyver,
            "libpython%d%dm.dll" % _pyver,
            "libpython%d.%d.dll" % _pyver,
            "libpython%d.%dm.dll" % _pyver,
        }
    else:
        if is_darwin:
            PYDYLIB_NAMES = {
                "Python",
                ".Python",
                "libpython%d.%d.dylib" % _pyver,
                "libpython%d.%dm.dylib" % _pyver,
            }
        else:
            if is_aix:
                PYDYLIB_NAMES = {
                    "libpython%d.%d.a" % _pyver,
                    "libpython%d.%d.so" % _pyver,
                }
            else:
                if is_freebsd:
                    PYDYLIB_NAMES = {
                        "libpython%d.%d.so.1" % _pyver,
                        "libpython%d.%dm.so.1" % _pyver,
                        "libpython%d.%d.so.1.0" % _pyver,
                        "libpython%d.%dm.so.1.0" % _pyver,
                    }
                else:
                    if is_hpux:
                        PYDYLIB_NAMES = {"libpython%d.%d.so" % _pyver}
                    else:
                        if is_unix:
                            PYDYLIB_NAMES = {
                                "libpython%d.%d.so.1.0" % _pyver,
                                "libpython%d.%dm.so.1.0" % _pyver,
                                "libpython%d.%dmu.so.1.0" % _pyver,
                            }
                        else:
                            raise SystemExit(
                                "Your platform is not yet supported. Please define constant PYDYLIB_NAMES for your platform."
                            )
                        open_file = open if is_py3 else io.open
                        if is_py2:
                            FileExistsError = OSError
                        else:
                            from builtins import FileExistsError
                        if is_py2:
                            from UserDict import UserDict
                            from collections import Sequence, Set
                        else:
                            from collections import UserDict
                            from collections.abc import Sequence, Set
                        try:
                            stdin_input = raw_input
                        except NameError:
                            stdin_input = input

                        if is_py2:
                            safe_repr = repr
                        else:
                            safe_repr = ascii
                        if is_py2:
                            string_types = basestring
                        else:
                            string_types = str
                        PYCO = "c"
                        _PYOPTS = ""
                        base_prefix = getattr(
                            sys, "real_prefix", getattr(sys, "base_prefix", sys.prefix)
                        )
                        base_prefix = os.path.abspath(base_prefix)
                        is_venv = is_virtualenv = base_prefix != os.path.abspath(
                            sys.prefix
                        )
                        is_conda = "conda" in sys.version or "Continuum" in sys.version
                        if is_py34:
                            import importlib.util

                            BYTECODE_MAGIC = importlib.util.MAGIC_NUMBER
                        else:
                            import imp

                            BYTECODE_MAGIC = imp.get_magic()
                        try:
                            from importlib.machinery import EXTENSION_SUFFIXES
                        except ImportError:
                            import imp

                            EXTENSION_SUFFIXES = [
                                f[0]
                                for f in imp.get_suffixes()
                                if f[2] == imp.C_EXTENSION
                            ]

                        if is_py2:
                            modname_tkinter = "Tkinter"
                        else:
                            modname_tkinter = "tkinter"
                        if is_win:
                            try:
                                from PyInstaller.utils.win32 import winutils

                                try:
                                    pywintypes = winutils.import_pywin32_module(
                                        "pywintypes", _is_venv=is_venv
                                    )
                                    win32api = winutils.import_pywin32_module(
                                        "win32api", _is_venv=is_venv
                                    )
                                except ImportError:
                                    try:
                                        from win32ctypes.pywin32 import pywintypes
                                        from win32ctypes.pywin32 import win32api
                                    except ImportError:
                                        raise

                            except ImportError:
                                if not os.environ.get("PYINSTALLER_NO_PYWIN32_FAILURE"):
                                    raise SystemExit(
                                        "PyInstaller cannot check for assembly dependencies.\nPlease install PyWin32 or pywin32-ctypes.\n\npip install pypiwin32\n"
                                    )

                            def architecture():
                                """
                                Returns the bit depth of the python interpreter's architecture as
                                a string ('32bit' or '64bit'). Similar to platform.architecture(),
                                but with fixes for universal binaries on MacOS.
                                """
                                if is_darwin:
                                    if sys.maxsize > 4294967296:
                                        return "64bit"
                                    return "32bit"
                                else:
                                    return platform.architecture()[0]

                            def system():
                                syst = platform.system()
                                if syst == "Microsoft":
                                    return "Windows"
                                else:
                                    return syst

                            def machine():
                                """
                                Return machine suffix to use in directory name when looking
                                for bootloader.
                                
                                PyInstaller is reported to work even on ARM architecture. For that
                                case functions system() and architecture() are not enough.
                                Path to bootloader has to be composed from system(), architecture()
                                and machine() like:
                                    'Linux-32bit-arm'
                                """
                                mach = platform.machine()
                                if mach.startswith("arm"):
                                    return "arm"
                                elif mach.startswith("aarch"):
                                    return "aarch"
                                else:
                                    return

                            def getenv(name, default=None):
                                """
                                Returns unicode string containing value of environment variable 'name'.
                                """
                                return os.environ.get(name, default)

                            def setenv(name, value):
                                """
                                Accepts unicode string and set it as environment variable 'name' containing
                                value 'value'.
                                """
                                os.environ[name] = value

                            def unsetenv(name):
                                """
                                Delete the environment variable 'name'.
                                """
                                os.environ[name] = ""
                                del os.environ[name]

                            def exec_command(*cmdargs, **kwargs):
                                """
                                Run the command specified by the passed positional arguments, optionally
                                configured by the passed keyword arguments.
                                
                                .. DANGER::
                                   **Ignore this function's return value** -- unless this command's standard
                                   output contains _only_ pathnames, in which case this function returns the
                                   correct filesystem-encoded string expected by PyInstaller. In all other
                                   cases, this function's return value is _not_ safely usable. Consider
                                   calling the general-purpose `exec_command_stdout()` function instead.
                                
                                   For backward compatibility, this function's return value non-portably
                                   depends on the current Python version and passed keyword arguments:
                                
                                   * Under Python 2.7, this value is an **encoded `str` string** rather than
                                     a decoded `unicode` string. This value _cannot_ be safely used for any
                                     purpose (e.g., string manipulation or parsing), except to be passed
                                     directly to another non-Python command.
                                   * Under Python 3.x, this value is a **decoded `str` string**. However,
                                     even this value is _not_ necessarily safely usable:
                                     * If the `encoding` parameter is passed, this value is guaranteed to be
                                       safely usable.
                                     * Else, this value _cannot_ be safely used for any purpose (e.g.,
                                       string manipulation or parsing), except to be passed directly to
                                       another non-Python command. Why? Because this value has been decoded
                                       with the encoding specified by `sys.getfilesystemencoding()`, the
                                       encoding used by `os.fsencode()` and `os.fsdecode()` to convert from
                                       platform-agnostic to platform-specific pathnames. This is _not_
                                       necessarily the encoding with which this command's standard output
                                       was encoded. Cue edge-case decoding exceptions.
                                
                                Parameters
                                ----------
                                cmdargs : list
                                    Variadic list whose:
                                    1. Mandatory first element is the absolute path, relative path,
                                       or basename in the current `${PATH}` of the command to run.
                                    1. Optional remaining elements are arguments to pass to this command.
                                encoding : str, optional
                                    Optional keyword argument specifying the encoding with which to decode
                                    this command's standard output under Python 3. As this function's return
                                    value should be ignored, this argument should _never_ be passed.
                                
                                All remaining keyword arguments are passed as is to the `subprocess.Popen()`
                                constructor.
                                
                                Returns
                                ----------
                                str
                                    Ignore this value. See discussion above.
                                """
                                encoding = kwargs.pop("encoding", None)
                                out = (
                                    subprocess.Popen(stdout=subprocess.PIPE, **kwargs)
                                ).communicate()[0]
                                if is_py3:
                                    try:
                                        if encoding:
                                            out = out.decode(encoding)
                                        else:
                                            out = os.fsdecode(out)
                                    except UnicodeDecodeError as e:
                                        print("--" * 20, file=sys.stderr)
                                        print(str(e), file=sys.stderr)
                                        print(
                                            "These are the bytes around the offending byte:",
                                            file=sys.stderr,
                                        )
                                        print("--" * 20, file=sys.stderr)
                                        raise

                                    return out

                            def exec_command_rc(*cmdargs, **kwargs):
                                """
                                Return the exit code of the command specified by the passed positional
                                arguments, optionally configured by the passed keyword arguments.
                                
                                Parameters
                                ----------
                                cmdargs : list
                                    Variadic list whose:
                                    1. Mandatory first element is the absolute path, relative path,
                                       or basename in the current `${PATH}` of the command to run.
                                    1. Optional remaining elements are arguments to pass to this command.
                                
                                All keyword arguments are passed as is to the `subprocess.call()` function.
                                
                                Returns
                                ----------
                                int
                                    This command's exit code as an unsigned byte in the range `[0, 255]`,
                                    where 0 signifies success and all other values failure.
                                """
                                if "encoding" in kwargs:
                                    kwargs.pop("encoding")
                                return subprocess.call(cmdargs, **kwargs)

                            def exec_command_stdout(*command_args, **kwargs):
                                """
                                Capture and return the standard output of the command specified by the
                                passed positional arguments, optionally configured by the passed keyword
                                arguments.
                                
                                Unlike the legacy `exec_command()` and `exec_command_all()` functions, this
                                modern function is explicitly designed for cross-platform portability. The
                                return value may be safely used for any purpose, including string
                                manipulation and parsing.
                                
                                .. NOTE::
                                   If this command's standard output contains _only_ pathnames, this
                                   function does _not_ return the correct filesystem-encoded string expected
                                   by PyInstaller. If this is the case, consider calling the
                                   filesystem-specific `exec_command()` function instead.
                                
                                Parameters
                                ----------
                                cmdargs : list
                                    Variadic list whose:
                                    1. Mandatory first element is the absolute path, relative path,
                                       or basename in the current `${PATH}` of the command to run.
                                    1. Optional remaining elements are arguments to pass to this command.
                                encoding : str, optional
                                    Optional name of the encoding with which to decode this command's
                                    standard output (e.g., `utf8`), passed as a keyword argument. If
                                    unpassed , this output will be decoded in a portable manner specific to
                                    to the current platform, shell environment, and system settings with
                                    Python's built-in `universal_newlines` functionality.
                                
                                All remaining keyword arguments are passed as is to the
                                `subprocess.check_output()` function.
                                
                                Returns
                                ----------
                                unicode or str
                                    Unicode string of this command's standard output decoded according to
                                    the "encoding" keyword argument. This string's type depends on the
                                    current Python version as follows:
                                    * Under Python 2.7, this is a decoded `unicode` string.
                                    * Under Python 3.x, this is a decoded `str` string.
                                """
                                encoding = kwargs.pop("encoding", None)
                                kwargs["universal_newlines"] = encoding is None
                                stdout = subprocess.check_output(command_args, **kwargs)
                                if encoding is None:
                                    return stdout
                                else:
                                    return stdout.decode(encoding)

                            def exec_command_all(*cmdargs, **kwargs):
                                """
                                Run the command specified by the passed positional arguments, optionally
                                configured by the passed keyword arguments.
                                
                                .. DANGER::
                                   **Ignore this function's return value.** If this command's standard
                                   output consists solely of pathnames, consider calling `exec_command()`;
                                   else, consider calling `exec_command_stdout()`.
                                
                                Parameters
                                ----------
                                cmdargs : list
                                    Variadic list whose:
                                    1. Mandatory first element is the absolute path, relative path,
                                       or basename in the current `${PATH}` of the command to run.
                                    1. Optional remaining elements are arguments to pass to this command.
                                encoding : str, optional
                                    Optional keyword argument specifying the encoding with which to decode
                                    this command's standard output under Python 3. As this function's return
                                    value should be ignored, this argument should _never_ be passed.
                                
                                All remaining keyword arguments are passed as is to the `subprocess.Popen()`
                                constructor.
                                
                                Returns
                                ----------
                                (int, str, str)
                                    Ignore this 3-element tuple `(exit_code, stdout, stderr)`. See the
                                    `exec_command()` function for discussion.
                                """
                                encoding = kwargs.pop("encoding", None)
                                proc = subprocess.Popen(
                                    bufsize=-1,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE,
                                    **kwargs
                                )
                                out, err = proc.communicate()
                                if is_py3:
                                    try:
                                        if encoding:
                                            out = out.decode(encoding)
                                            err = err.decode(encoding)
                                        else:
                                            out = os.fsdecode(out)
                                            err = os.fsdecode(err)
                                    except UnicodeDecodeError as e:
                                        print("--" * 20, file=sys.stderr)
                                        print(str(e), file=sys.stderr)
                                        print(
                                            "These are the bytes around the offending byte:",
                                            file=sys.stderr,
                                        )
                                        print("--" * 20, file=sys.stderr)
                                        raise

                                    return (proc.returncode, out, err)

                            def __wrap_python(args, kwargs):
                                cmdargs = [sys.executable]
                                if is_darwin:
                                    mapping = {"32bit": "-i386", "64bit": "-x86_64"}
                                    py_prefix = ["arch", mapping[architecture()]]
                                    if "DYLD_LIBRARY_PATH" in os.environ:
                                        path = os.environ["DYLD_LIBRARY_PATH"]
                                        py_prefix += [
                                            "-e",
                                            "DYLD_LIBRARY_PATH=%s" % path,
                                        ]
                                    cmdargs = py_prefix + cmdargs
                                if _PYOPTS:
                                    cmdargs.append(_PYOPTS)
                                cmdargs.extend(args)
                                env = kwargs.get("env")
                                if env is None:
                                    env = dict(**os.environ)
                                if is_py3:
                                    env["PYTHONIOENCODING"] = "UTF-8"
                                    kwargs["encoding"] = "UTF-8"
                                return (cmdargs, kwargs)

                            def exec_python(*args, **kwargs):
                                """
                                Wrap running python script in a subprocess.
                                
                                Return stdout of the invoked command.
                                """
                                cmdargs, kwargs = __wrap_python(args, kwargs)
                                return exec_command(*cmdargs, **kwargs)

                            def exec_python_rc(*args, **kwargs):
                                """
                                Wrap running python script in a subprocess.
                                
                                Return exit code of the invoked command.
                                """
                                cmdargs, kwargs = __wrap_python(args, kwargs)
                                return exec_command_rc(*cmdargs, **kwargs)

                            def getcwd():
                                """
                                Wrap os.getcwd()
                                
                                On Windows return ShortPathName (8.3 filename) that contain only ascii
                                characters.
                                """
                                cwd = os.getcwd()
                                if is_win:
                                    pass
                                if is_py2:
                                    try:
                                        unicode(cwd)
                                    except UnicodeDecodeError:
                                        try:
                                            cwd = win32api.GetShortPathName(cwd)
                                        except ImportError:
                                            pass

                                    return cwd

                            def expand_path(path):
                                """
                                Replace initial tilde '~' in path with user's home directory and also
                                expand environment variables (${VARNAME} - Unix, %VARNAME% - Windows).
                                """
                                return os.path.expandvars(os.path.expanduser(path))

                            try:
                                from shutil import which
                            except ImportError:

                                def which(cmd, mode=os.F_OK | os.X_OK, path=None):
                                    """Given a command, mode, and a PATH string, return the path which
                                    conforms to the given mode on the PATH, or None if there is no such
                                    file.
                                    
                                    `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
                                    of os.environ.get("PATH"), or can be overridden with a custom search
                                    path.
                                    
                                    """

                                    def _access_check(fn, mode):
                                        return (
                                            os.path.exists(fn)
                                            and os.access(fn, mode)
                                            and not os.path.isdir(fn)
                                        )

                                    if os.path.dirname(cmd):
                                        if _access_check(cmd, mode):
                                            return cmd
                                        return
                                    if path is None:
                                        path = os.environ.get("PATH", os.defpath)
                                    if not path:
                                        return
                                    path = path.split(os.pathsep)
                                    if sys.platform == "win32":
                                        if os.curdir not in path:
                                            path.insert(0, os.curdir)
                                        pathext = os.environ.get("PATHEXT", "").split(
                                            os.pathsep
                                        )
                                        if any(
                                            (
                                                cmd.lower().endswith(ext.lower())
                                                for ext in pathext
                                            )
                                        ):
                                            files = [cmd]
                                        else:
                                            files = [cmd + ext for ext in pathext]
                                    else:
                                        files = [cmd]
                                    seen = set()
                                    for dir in path:
                                        normdir = os.path.normcase(dir)
                                        if normdir not in seen:
                                            seen.add(normdir)
                                            for thefile in files:
                                                name = os.path.join(dir, thefile)
                                                if _access_check(name, mode):
                                                    return name

                            if hasattr(site, "getsitepackages"):
                                getsitepackages = site.getsitepackages
                            else:

                                def getsitepackages():
                                    """
                                    Return only one item as list with one item.
                                    """
                                    if is_win:
                                        pths = [
                                            os.path.join(
                                                sys.prefix, "Lib", "site-packages"
                                            )
                                        ]
                                        if is_virtualenv:
                                            pths.append(
                                                os.path.join(
                                                    base_prefix, "Lib", "site-packages"
                                                )
                                            )
                                        return pths
                                    raise NotImplementedError()

                            try:
                                from importlib import reload as module_reload
                            except ImportError:
                                from imp import reload as module_reload

                            if is_py2:
                                import imp

                                importlib_load_source = imp.load_source
                            else:
                                import importlib.machinery

                                def importlib_load_source(name, pathname):
                                    mod_loader = importlib.machinery.SourceFileLoader(
                                        name, pathname
                                    )
                                    return mod_loader.load_module()

                            try:
                                FileNotFoundError_ = FileNotFoundError
                            except NameError:

                                class FileNotFoundError(OSError):
                                    pass

                            else:
                                FileNotFoundError = FileNotFoundError_
                                del FileNotFoundError_

                            PY3_BASE_MODULES = {
                                "_weakrefset",
                                "abc",
                                "codecs",
                                "collections",
                                "copyreg",
                                "encodings",
                                "functools",
                                "io",
                                "heapq",
                                "keyword",
                                "linecache",
                                "locale",
                                "operator",
                                "re",
                                "reprlib",
                                "sre_compile",
                                "sre_constants",
                                "sre_parse",
                                "traceback",
                                "types",
                                "weakref",
                            }
                            if sys.version_info[0] == 3:
                                if sys.version_info[1] >= 4:
                                    PY3_BASE_MODULES.update(
                                        {"_bootlocale", "_collections_abc"}
                                    )
                            PURE_PYTHON_MODULE_TYPES = {
                                "SourceModule",
                                "CompiledModule",
                                "Package",
                                "NamespacePackage",
                                "FlatPackage",
                                "ArchiveModule",
                            }
                            SPECIAL_MODULE_TYPES = {
                                "AliasNode",
                                "BuiltinModule",
                                "RuntimeModule",
                                "RuntimePackage",
                                "Script",
                            }
                            BINARY_MODULE_TYPES = {"Extension"}
                            VALID_MODULE_TYPES = (
                                PURE_PYTHON_MODULE_TYPES
                                | SPECIAL_MODULE_TYPES
                                | BINARY_MODULE_TYPES
                            )
                            BAD_MODULE_TYPES = {
                                "BadModule",
                                "ExcludedModule",
                                "InvalidSourceModule",
                                "InvalidCompiledModule",
                                "MissingModule",
                                "RuntimeModule",
                                "RuntimePackage",
                            }
                            ALL_MODULE_TYPES = VALID_MODULE_TYPES | BAD_MODULE_TYPES
                            MODULE_TYPES_TO_TOC_DICT = {
                                "AliasNode": "PYMODULE",
                                "Script": "PYSOURCE",
                                "SourceModule": "PYMODULE",
                                "CompiledModule": "PYMODULE",
                                "Package": "PYMODULE",
                                "FlatPackage": "PYMODULE",
                                "ArchiveModule": "PYMODULE",
                                "Extension": "EXTENSION",
                                "BuiltinModule": "BUILTIN",
                                "NamespacePackage": "PYMODULE",
                                "BadModule": "bad",
                                "ExcludedModule": "excluded",
                                "InvalidSourceModule": "invalid",
                                "InvalidCompiledModule": "invalid",
                                "MissingModule": "missing",
                                "RuntimeModule": "runtime",
                                "RuntimePackage": "runtime",
                                "does not occur": "BINARY",
                            }

                            def check_requirements():
                                """
                                Verify that all requirements to run PyInstaller are met.
                                
                                Fail hard if any requirement is not met.
                                """
                                if sys.version_info < (3, 3):
                                    if sys.version_info[:2] != (2, 7):
                                        raise SystemExit(
                                            "PyInstaller requires at least Python 2.7 or 3.3+."
                                        )

                            if not is_py34:

                                class suppress(object):
                                    """Context manager to suppress specified exceptions
                                    After the exception is suppressed, execution proceeds with the next
                                    statement following the with statement.
                                         with suppress(FileNotFoundError):
                                             os.remove(somefile)
                                         # Execution still resumes here if the file was already removed
                                    """

                                    def __init__(self, *exceptions):
                                        self._exceptions = exceptions

                                    def __enter__(self):
                                        pass

                                    def __exit__(self, exctype, excinst, exctb):
                                        return exctype is not None and issubclass(
                                            exctype, self._exceptions
                                        )

                            else:
                                from contextlib import suppress
